import json
import os
import requests
from PyQt5 import Qt, QtCore
from PyQt5.QtCore import QTimer, QThread, pyqtSignal
from PyQt5.QtWidgets import QDialog, QApplication
from requests.auth import HTTPBasicAuth
from tqdm import tqdm

from upgrade_ui import Ui_Dialog

class AsyncWorker(QThread):
    def __init__(self, func, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.result = False

    def run(self):
        # print("start run")
        self.result = self.func(*self.args, **self.kwargs)
        # print("stop run")

class UpgradeUI(Ui_Dialog, QDialog):
    DEFAULT_WINDOWTITLE = 'Upgrade Application V1.00'
    DEFAULT_BASEURL = "http://10.10.10.203/"
    DEFAULT_CONFIGSFILE = "configs.json"
    USERNAME = "upload"
    PASSWORD = "upload"
    progress_updated = pyqtSignal(int)
    label_updated = pyqtSignal(str)
    dialog_close = pyqtSignal()

    def __init__(self, parent=None):
        # 创建是不能继承photoarchiver,否则拖动photoarchiver会导致本窗口异常缩小
        super().__init__(None)
        self.setupUi(self)
        # self.setWindowModality(Qt.WindowModality.NonModal)
        self.setWindowTitle(self.DEFAULT_WINDOWTITLE)
        self.setWindowFlags(QtCore.Qt.WindowType.Window | QtCore.Qt.WindowType.CustomizeWindowHint | QtCore.Qt.WindowType.WindowCloseButtonHint)
        self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowType.WindowMaximizeButtonHint)
        self.setFixedSize(self.size())

        self.parent = parent
        self.progressbar.setValue(0)
        config_update = False

        if os.path.exists(self.DEFAULT_CONFIGSFILE):
            with open(self.DEFAULT_CONFIGSFILE, "r") as file:
                configs = json.load(file)
        else:
            configs = {
                "baseurl":self.DEFAULT_BASEURL
            }
            config_update = True
        if configs.get('baseurl') is None:
            configs['baseurl'] = self.DEFAULT_BASEURL
            config_update = True
        if config_update:
            with open(self.DEFAULT_CONFIGSFILE, "w") as file:
                json.dump(configs, file, indent=2)

        self.lineedit_baseurl.setText(configs['baseurl'])
        self.lineedit_baseurl.setEnabled(False)

        self.auth = HTTPBasicAuth(self.USERNAME, self.PASSWORD)
        self.session = requests.Session()
        self.session.auth = self.auth
        self.progress_updated.connect(self.update_progress)
        self.dialog_close.connect(self.close)
        self.label_updated.connect(self.setLabelInfo)
        self.imageconfigs = []

        self.activateWindow()
        self.raise_()

    def setLabelInfo(self, text):
        self.label_info.setText(text)

    def editsave(self):
        if self.button_editsave.text() == "Edit":
            # edit
            self.button_editsave.setText("Save")
            self.lineedit_baseurl.setEnabled(True)
        else:
            # save
            self.button_editsave.setText("Edit")
            self.lineedit_baseurl.setEnabled(False)
            if len(self.lineedit_baseurl.text().strip()) != 0:
                configs = {
                    "serverip": self.lineedit_baseurl.text()
                }
                with open(self.DEFAULT_CONFIGSFILE, "w") as file:
                    json.dump(configs, file, indent=2)

    def update_progress(self, value):
        self.progressbar.setValue(value)

    def upload_file(self, local_file_path, remote_file_name=None):
        """上传文件到服务器并显示进度条"""
        try:
            if not remote_file_name:
                remote_file_name = os.path.basename(local_file_path)
            base_url = self.lineedit_baseurl.text().strip()
            upload_url = f"{base_url}/uploads/{remote_file_name}"
            file_size = os.path.getsize(local_file_path)

            with open(local_file_path, 'rb') as file:
                # 创建进度条
                progress_bar = tqdm(
                    total=file_size,
                    unit='B',
                    unit_scale=True,
                    desc=f"上传 {remote_file_name}"
                )
                file_content = file.read()  # 一次性读取整个文件
                # 分块上传并更新进度条
                response = self.session.put(
                    upload_url,
                    # data=self._read_in_chunks(file, progress_bar),
                    data=file_content,
                    headers={'Content-Length': str(file_size)},
                    auth=(self.USERNAME, self.PASSWORD)
                )
                progress_bar.close()

            if response.status_code in (200, 201, 204):
                print(f"文件 '{local_file_path}' 上传成功")
                return True
            else:
                print(f"上传失败，状态码: {response.status_code}")
                print(f"错误信息: {response.text}")
                return False

        except Exception as e:
            print(f"上传过程中发生错误: {str(e)}")
            return False

    def _read_in_chunks(self, file_object, progress_bar, chunk_size=8192):
        """分块读取文件并更新进度条"""
        while True:
            data = file_object.read(chunk_size)
            if not data:
                break
            progress_bar.update(len(data))
            yield data

    def download_description(self, modelname, model_filename):
        self.imageconfigs = {
            'url':[],
            'checksum':[],
            'filename':[],
            'modelname':[],
        }
        try:
            print(f'download description {modelname}')
            self.setLabelInfo(f'Downloading description file: {modelname} ...')
            base_url = self.lineedit_baseurl.text().strip()
            download_url = f"{base_url}/downloads/{modelname}/{model_filename}"

            response = requests.get(download_url, auth=(self.USERNAME, self.PASSWORD), timeout=1)
            if response.status_code == 200:
                print("认证成功，文件内容：")
                print(response.text)
                lines = response.text.splitlines()

                for line in lines:
                    checksum, filename = line.split()
                    self.imageconfigs['url'].append(f"{base_url}/downloads/{modelname}/{filename}")
                    self.imageconfigs['checksum'].append(checksum)
                    self.imageconfigs['filename'].append(os.path.basename(filename))
                    self.imageconfigs['modelname'].append(modelname)
            else:
                print(f"认证失败，状态码：{response.status_code}")
        except requests.exceptions.RequestException as e:
            print(f"请求失败：{e}")
            return False

        return True


    def download_file(self, remote_file_name, local_dir='.'):
        """从服务器下载文件并显示进度条"""
        try:
            if not remote_file_name.lower().startswith("http"):
                base_url = self.lineedit_baseurl.text().strip()
                download_url = f"{base_url}/downloads/{remote_file_name}"
            else:
                 download_url = remote_file_name
            if local_dir != '':
                os.makedirs(local_dir, exist_ok=True)
            local_file_path = os.path.join(local_dir, os.path.basename(download_url))
            print(f'downloading {os.path.basename(remote_file_name)}')
            self.setLabelInfo(f'Downloading {os.path.basename(remote_file_name)} ...')
            # 先获取文件大小
            head_response = self.session.head(download_url, timeout=5)
            if head_response.status_code != 200:
                print(f"获取文件信息失败，状态码: {head_response.status_code}")
                return False

            file_size = int(head_response.headers.get('Content-Length', 0))

            # 开始下载
            response = self.session.get(download_url, stream=True)

            if response.status_code == 200:
                # 创建进度条
                progress_bar = tqdm(
                    total=file_size,
                    unit='B',
                    unit_scale=True,
                    desc=f"下载 {remote_file_name}"
                )

                # 分块写入并更新进度条
                size = 0
                self.progress_updated.emit(0)
                with open(local_file_path, 'wb') as file:
                    for chunk in response.iter_content(chunk_size=8192):
                        if chunk:
                            file.write(chunk)
                            progress_bar.update(len(chunk))
                            size += len(chunk)
                            self.progress_updated.emit(int(size * 100 / file_size))
                progress_bar.close()

                print(f"文件 '{remote_file_name}' 下载成功，保存至: {local_file_path}")
                return True
            elif response.status_code == 404:
                print(f"下载失败，文件 '{remote_file_name}' 不存在")
                return False
            else:
                print(f"下载失败，状态码: {response.status_code}")
                print(f"错误信息: {response.text}")
                return False

        except Exception as e:
            print(f"下载过程中发生错误: {str(e)}")
            return False

